<!--
 * @Author: Xujianchen
 * @Date: 2024-06-29 09:52:00
 * @LastEditors: Xujianchen
 * @LastEditTime: 2025-01-18 09:56:18
 * @Description: 图标选择组件
-->
<template>
  <div class="icon-select">
    <div
      class="icon-select-wrapper"
      :class="{ hasValue: modelValue }"
      @click="openModal"
    >
      <el-input v-model="modelValue" :disabled="disabled" readonly>
        <template #prefix>
          <icon :name="modelValue || 'Plus'" :type="type" />
        </template>
      </el-input>
    </div>

    <Modal
      v-model="visible"
      title="图标选择器"
      top="5vh"
      :show-footer="false"
      :show-fullscreen="false"
      @close="() => close({ value: '' })"
    >
      <el-input
        v-model="keyword"
        prefix-icon="Search"
        placeholder="搜索图标"
        clearable
      />
      <el-tabs v-model="activeIndex" class="icon-select-tabs">
        <el-tab-pane
          v-for="item in iconList"
          :key="item.name"
          :name="item.name"
          lazy
        >
          <template #label>
            <el-space>
              {{ item.iconType }}
              <el-tag type="info">{{ item.icons.length }}</el-tag>
            </el-space>
          </template>
          <div class="icon-select-list">
            <div
              v-for="iconItem in item.icons"
              :key="iconItem.name"
              class="icon-select-list-item flex"
              @click="selectIcon(iconItem)"
            >
              <icon :name="iconItem.value" :type="item.iconType" size="30" />
            </div>
          </div>
        </el-tab-pane>
      </el-tabs>
    </Modal>
  </div>
</template>

<script setup>
import { ElIcons } from '@/app/element-plus-icons'
import { ICON_TYPE } from '@/const'
import { ModalEmits } from '@/components/modal/emit'

const modelValue = defineModel({ type: String, default: '' })
const props = defineProps({
  placeholder: {
    type: String,
    default: '请输入或者选择图标',
  },
  iconType: {
    type: String,
    default: ICON_TYPE.EL_ICON,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  clearable: {
    type: Boolean,
    default: false,
  },
})
const emit = defineEmits([...ModalEmits, 'select'])

const elIcons = generateIcons(ICON_TYPE.EL_ICON)
const svgIcons = generateIcons()
const visible = ref(false)
const keyword = ref('')
const type = ref(props.iconType)
const activeIndex = ref(0)
const iconList = ref([
  { iconType: ICON_TYPE.EL_ICON, icons: elIcons, name: 0 },
  { iconType: ICON_TYPE.SVG, icons: svgIcons, name: 1 },
])

watch(keyword, (newVal) => search(newVal))

function openModal() {
  if (props.disabled) return
  visible.value = true
}

function search(text) {
  const icons = iconList.value
  const index = activeIndex.value

  if (text) {
    const current = icons[index]
    iconList.value[index].icons = current.icons.filter((n) =>
      n.name.toLowerCase().includes(text.toLowerCase()),
    )
  } else {
    iconList.value = [...elIcons, ...svgIcons]
  }
}

function selectIcon(item) {
  type.value = item.iconType
  modelValue.value = item.value
  emit('select', item)
  close()
}

function close() {
  visible.value = false
  keyword.value = ''
}

function generateIcons(iconType = ICON_TYPE.SVG) {
  let iconList = []
  if (iconType === ICON_TYPE.SVG) {
    const modules = import.meta.glob('/src/assets/svg/*.svg')
    iconList = Object.keys(modules).map((key) => {
      const name = key.replace(/^.*\/(\S+)\..*/, '$1')
      return {
        name,
        value: name,
        iconType: ICON_TYPE.SVG,
      }
    })
  } else {
    iconList = Object.keys(ElIcons).map((item) => ({
      name: item,
      value: item,
      iconType: ICON_TYPE.EL_ICON,
    }))
  }

  return iconList
}
</script>

<style lang="scss" scoped>
.icon-select {
  display: inline-flex;

  &-wrapper {
    cursor: pointer;
    display: inline-flex;

    :deep(.el-input__inner) {
      flex-grow: 0;
      width: 0;
    }

    :deep(.el-input__icon) {
      margin: 0;
      font-size: var(--el-font-size-medium);
    }

    :deep(.el-input__prefix-inner > :last-child) {
      margin-right: 0;
    }
  }

  &-list {
    display: flex;
    flex-wrap: wrap;
    max-height: 360px;
    overflow: auto;

    &-item {
      width: 80px;
      height: 80px;
      border-radius: 4px;
      margin: $space-small;
      transition: all 0.1s;
      box-shadow: 0 0 0 1px #eee;
      justify-content: center;

      &:hover {
        box-shadow: 0 0 1px 3px var(--el-color-primary);
        background-color: var(--el-color-primary-light-9);

        i {
          color: var(--el-color-primary);
        }
      }
    }
  }

  &-tabs {
    margin-top: $space-medium-x;
  }
}

// 暗黑模式样式
.dark {
  .icon-select-list li {
    box-shadow: 0 0 0 1px #333;

    &:hover {
      box-shadow: 0 0 1px 3px rgba(var(--el-color-primary), 1);
    }

    i {
      background-color: var(--el-bg-color);
    }
  }
}
</style>
